package com.nbufe.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nbufe.domain.ResponseResult;
import com.nbufe.domain.dto.trade.CarbonTradeDto;
import com.nbufe.domain.dto.trade.QueryTradePage;
import com.nbufe.domain.entity.CarbonStatistics;
import com.nbufe.domain.entity.CarbonTrading;
import com.nbufe.domain.vo.PageVo;
import com.nbufe.domain.vo.trade.CarbonMarketVo;
import com.nbufe.domain.vo.trade.EuropeCarbonMarketVo;
import com.nbufe.domain.vo.trade.TradeVo;
import com.nbufe.domain.vo.trade.tradeCompareVo;
import com.nbufe.mapper.CarbonTradingMapper;
import com.nbufe.service.CarbonStatisticsService;
import com.nbufe.service.CarbonTradingService;
import com.nbufe.service.DataService;
import com.nbufe.utils.DateUtil;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.time.LocalDate;
import java.util.*;

/**
 * @Author luzhiheng
 * @Date 2024/1/25 15:26
 */
@Service
public class CarbonTradingServiceImpl extends ServiceImpl<CarbonTradingMapper, CarbonTrading> implements CarbonTradingService {

    @Resource
    private DataService dataService;

    @Resource
    private CarbonStatisticsService carbonStatisticsService;

    @Override
    public ResponseResult queryMarketInfo(Integer type) {
        if (type == 0) {
//            String url = "http://k.tanjiaoyi.com/#l";
//            String url3 = "http://zhishu.tanjiaoyi.com/";
            String url2 = "https://carbonmarket.cn/ets/cets/";
            Document document = null;
            try {
                document = Jsoup.connect(url2)
                        .ignoreContentType(true)
                        .ignoreHttpErrors(true)
                        .get();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            Elements elements = document.getElementsByClass("table table-hover text-center");
            Elements trElements = elements.get(0).getElementsByTag("tr");

            List<CarbonMarketVo> carbonMarketVoList = new ArrayList<>();
            trElements.forEach(tr -> {
                Elements tdElements = tr.getElementsByTag("td");
                if (tdElements.size() > 0) {
                    List<String> infoList = new ArrayList<>();
                    tdElements.forEach(td -> {
                        String html = td.html();
                        infoList.add(html);
                    });
                    carbonMarketVoList.add(new CarbonMarketVo(infoList));
                }
            });
            return ResponseResult.okResult(carbonMarketVoList);
        } else if (type == 12) {
            String url = "https://carbonmarket.cn/ets/weekly/";
            Document document = null;
            try {
                document = Jsoup.connect(url)
                        .ignoreContentType(true)
                        .ignoreHttpErrors(true)
                        .get();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            Elements elements = document.getElementsByClass("table table-hover text-center");
            Elements trElements = elements.get(0).getElementsByTag("tr");

            List<CarbonMarketVo> carbonMarketVoList = new ArrayList<>();
            trElements.forEach(tr -> {
                Elements tdElements = tr.getElementsByTag("td");
                if (tdElements.size() > 0) {
                    List<String> infoList = new ArrayList<>();
                    tdElements.forEach(td -> {
                        String html = td.html();
                        infoList.add(html);
                    });
                    carbonMarketVoList.add(new CarbonMarketVo(infoList));
                }
            });
            return ResponseResult.okResult(carbonMarketVoList);
        } else {
            String url = "";
            if (type == 1) {
                url = "https://carbonmarket.cn/ets/eu/";
            } else if (type == 2) {
                url = "https://carbonmarket.cn/ets/us/";
            } else if (type == 3) {
                url = "https://carbonmarket.cn/ets/kr/";
            } else if (type == 4) {
                url = "https://carbonmarket.cn/ets/beijing/";
            } else if (type == 5) {
                url = "https://carbonmarket.cn/ets/shanghai/";
            } else if (type == 6) {
                url = "https://carbonmarket.cn/ets/shenzhen/";
            } else if (type == 7) {
                url = "https://carbonmarket.cn/ets/guangdong/";
            } else if (type == 8) {
                url = "https://carbonmarket.cn/ets/tianjin/";
            } else if (type == 9) {
                url = "https://carbonmarket.cn/ets/chongqing/";
            } else if (type == 10) {
                url = "https://carbonmarket.cn/ets/hubei/";
            } else if (type == 11) {
                url = "https://carbonmarket.cn/ets/fujian/";
            }
            try {
                Document document = Jsoup.connect(url)
                        .ignoreContentType(true)
                        .ignoreHttpErrors(true)
                        .get();
                Elements elements = document.getElementsByClass("blog-wrap-text");
                Element element = elements.get(0);
                Elements trElements = element.getElementsByTag("tr");
                List<EuropeCarbonMarketVo> europeCarbonMarketVoList = new ArrayList<>();
                for (Element trElement : trElements) {
                    Elements tdElements = trElement.getElementsByTag("td");
                    if (tdElements.size() == 0) {
                        continue;
                    }
                    EuropeCarbonMarketVo europeCarbonMarketVo = new EuropeCarbonMarketVo();
                    europeCarbonMarketVo.setYear(tdElements.get(0).text());
                    europeCarbonMarketVo.setPrice(tdElements.get(1).text());
                    europeCarbonMarketVoList.add(europeCarbonMarketVo);
                }
                return ResponseResult.okResult(europeCarbonMarketVoList);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    @Override
    public ResponseResult queryCarbonAssertInfo() {
        LocalDate now = LocalDate.now();
        int year = now.getYear();

        // ccer
        Double ccer = 0.0;
        // 碳配额
        Double quota = 0.0;
        // 政府发放配额
        Double govQuota = 0.0;
        //应清缴碳配额
        Double needPayQuota = carbonStatisticsService.getNeedPayQuota();

        LambdaQueryWrapper<CarbonTrading> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(CarbonTrading::getCreateTime, LocalDate.now().getYear() + "%");
        List<CarbonTrading> carbonTradingList = this.list(queryWrapper);
        for (CarbonTrading carbonTrading : carbonTradingList) {
            Integer type = carbonTrading.getTradeType();
            Integer quotaType = carbonTrading.getQuotaType();
            Double tradeQuantity = carbonTrading.getTradeQuantity();
            if (type == 2) {
                govQuota += tradeQuantity == null ? 0 : tradeQuantity;
            } else {
                if (quotaType == 0) {
                    //配额
                    quota += tradeQuantity;
                } else if (quotaType == 1) {
                    //ccer
                    ccer += tradeQuantity;
                }
            }
        }


        Map<String, Double> map = new HashMap<>();
        map.put("ccer", ccer == null ? 0 : ccer);
        map.put("quota", quota == null ? 0 : quota);
        map.put("govQuota", govQuota == null ? 0 : govQuota);
        map.put("needPayQuota", needPayQuota);
        return ResponseResult.okResult(map);
    }

    @Override
    public ResponseResult queryCurrentCarbonAssert() {
        CarbonStatistics statistics = null;
        try {
            statistics = carbonStatisticsService.list().get(0);
        } catch (Exception e) {
            e.printStackTrace();
        }

        Double usedCcer = statistics.getUsedCcer();
        Double usedQuota = statistics.getUsedQuota();
        Map<String, Double> map = new HashMap<>();
        map.put("quota", queryTotalQuota() - usedQuota);
        map.put("ccer", queryTotalCCER() - usedCcer);
        return ResponseResult.okResult(map);
    }

    @Override
    public ResponseResult queryCarbonTradeCompare() {
        int year = LocalDate.now().getYear();
        List<CarbonTrading> carbonTradingList = baseMapper.queryAllTrade(year);
        Map<String, List<CarbonTrading>> monthMap = new HashMap<>();
        for (CarbonTrading carbonTrading : carbonTradingList) {
            Integer month = Integer.valueOf(DateUtil.formatMM(carbonTrading.getCreateTime()));
            Integer tradeType = carbonTrading.getTradeType();
            if (CollectionUtils.isEmpty(monthMap.get(month + "-" + tradeType))) {
                List<CarbonTrading> tradingList = new ArrayList<>();
                tradingList.add(carbonTrading);
                monthMap.put(month + "-" + tradeType, tradingList);
            } else {
                List<CarbonTrading> tradingList = monthMap.get(month + "-" + tradeType);
                tradingList.add(carbonTrading);
                monthMap.put(month + "-" + tradeType, tradingList);
            }
        }

        List<tradeCompareVo> tradeCompareVoList = new ArrayList<>();
        for (int i = 1; i <= 12; i++) {
            tradeCompareVo tradeCompareVo = new tradeCompareVo();
            tradeCompareVo.setMonth(i);
            String sellKey = i + "-" + 0;
            String buyKey = i + "-" + 1;
            List<CarbonTrading> sellTradingList = monthMap.get(sellKey);
            List<CarbonTrading> buyTradingList = monthMap.get(buyKey);
            if (CollectionUtils.isEmpty(sellTradingList)) {
                tradeCompareVo.setSell(0.0);
            } else {
                tradeCompareVo.setSell(sellTradingList.stream().mapToDouble(CarbonTrading::getTradeQuantity).sum());
            }
            if (CollectionUtils.isEmpty(buyTradingList)) {
                tradeCompareVo.setBuy(0.0);
            } else {
                tradeCompareVo.setBuy(buyTradingList.stream().mapToDouble(CarbonTrading::getTradeQuantity).sum());
            }
            tradeCompareVoList.add(tradeCompareVo);
        }
        return ResponseResult.okResult(tradeCompareVoList);
    }

    @Override
    public ResponseResult queryCarbonAssertCompare() {

        return null;
    }

    @Override
    public ResponseResult queryTradeList(QueryTradePage queryTradePage) {
        Page<CarbonTrading> page = new Page<>(queryTradePage.getPageNum(), queryTradePage.getPageSize());
        QueryWrapper<CarbonTrading> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(!Objects.isNull(queryTradePage.getAssertType()), "quota_type", queryTradePage.getAssertType());
        queryWrapper.eq(!Objects.isNull(queryTradePage.getTradeType()), "trade_type", queryTradePage.getTradeType());
        queryWrapper.orderByDesc("create_time");

//        List<Map<String, String>> sortArr = queryTradePage.getSortArr();
//        if (sortArr.size() > 0) {
//            for (Map<String, String> map : sortArr) {
//                String order = map.get("order");
//                String prop = map.get("prop");
//                prop = UnderUtil.camel2under(prop);
//                if ("ascending".equals(order)) {
//                    queryWrapper.orderByAsc(prop);
//                } else if ("descending".equals(order)) {
//                    queryWrapper.orderByDesc(prop);
//                }
//            }
//        }
        page(page, queryWrapper);

        PageVo pageVo = new PageVo(page.getTotal(), page.getRecords());
        return ResponseResult.okResult(pageVo);
    }

    @Override
    public Double queryTotalCCER() {
        LambdaQueryWrapper<CarbonTrading> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CarbonTrading::getQuotaType, 1);
        List<CarbonTrading> carbonTradingList = this.list(queryWrapper);
        double sum = carbonTradingList.stream()
                .filter(e -> e.getTradeQuantity() != null)
                .mapToDouble(CarbonTrading::getTradeQuantity).sum();
        return sum;
    }

    @Override
    public Double queryTotalQuota() {
        LambdaQueryWrapper<CarbonTrading> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CarbonTrading::getQuotaType, 0);
        List<CarbonTrading> carbonTradingList = this.list(queryWrapper);
        double sum = carbonTradingList.stream()
                .filter(e -> e.getTradeQuantity() != null)
                .mapToDouble(CarbonTrading::getTradeQuantity).sum();
        return sum;
    }

    @Override
    public ResponseResult queryCarbonAssert() {
        CarbonStatistics statistics = null;
        try {
            statistics = carbonStatisticsService.list().get(0);
        } catch (Exception e) {
            log.error(e.getMessage());
            statistics = new CarbonStatistics();
            statistics.setDelFlag(0);
            statistics.setCreateTime(new Date());
            statistics.setUsedCcer(0.0);
            statistics.setUsedQuota(0.0);
            statistics.setTotalCcer(0.0);
            statistics.setTotalQuota(0.0);
            carbonStatisticsService.save(statistics);
        }
        // 查询可用碳配额
        Double usedQuota = statistics.getUsedQuota();
        double ableQuota = statistics.getTotalQuota() - usedQuota;
        // 查询可用ccer
        Double usedCcer = statistics.getUsedCcer();
        double ableCcer = statistics.getTotalCcer() - usedCcer;
        Map<String, Object> map = new HashMap<>();
        map.put("usedQuota", usedQuota);
        map.put("usedCcer", usedCcer);
        map.put("ableQuota", ableQuota <= 0 ? 0 : ableCcer);
        map.put("ableCcer", ableCcer <= 0 ? 0 : ableCcer);
        return ResponseResult.okResult(map);
    }

    @Override
    public ResponseResult carbonAssertTrade(Map<String, Object> map) {
        double useNum = 0;
        try {
            useNum = (double) map.get("num");
        } catch (Exception e) {
            useNum = (int) map.get("num");
        }
        int type = (int) map.get("type");
        CarbonStatistics statistics = carbonStatisticsService.list().get(0);
        if (type == 1) {
            statistics.setUsedQuota(statistics.getUsedQuota() + useNum);
        } else {
            statistics.setUsedCcer(statistics.getUsedCcer() + useNum);
        }
        carbonStatisticsService.updateById(statistics);
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult carbonEmissionCompare() {
        CarbonStatistics statistics = null;
        try {
            statistics = carbonStatisticsService.list().get(0);
        } catch (Exception e) {
            log.error(e.getMessage());
            statistics = new CarbonStatistics();
            statistics.setDelFlag(0);
            statistics.setCreateTime(new Date());
            statistics.setUsedCcer(0.0);
            statistics.setUsedQuota(0.0);
            statistics.setTotalCcer(0.0);
            statistics.setTotalQuota(0.0);
            carbonStatisticsService.save(statistics);
        }
        // 查询可用碳配额
        Double usedQuota = statistics.getUsedQuota();
        double ableQuota = statistics.getTotalQuota() - usedQuota;
        // 查询可用ccer
        Double usedCcer = statistics.getUsedCcer();
        double ableCcer = statistics.getTotalCcer() - usedCcer;
        Map<String, Object> map = new HashMap<>();
        map.put("ableQuota", ableQuota);
        map.put("ableCcer", ableCcer);
        Double total = dataService.curYearEmission();
        map.put("yearEmission", total);
        return ResponseResult.okResult(map);
    }

    @Override
    public ResponseResult queryNewPrice() {
        List<TradeVo> tradeVoList = new ArrayList<>();
        ResponseResult result = queryMarketInfo(0);
        List list = (List) result.getData();
        CarbonMarketVo carbonMarketVo = (CarbonMarketVo) list.get(0);
        String price = carbonMarketVo.getInfoList().get(1);
        String str = "";
        for (char ch : price.toCharArray()) {
            if ((ch >= '0' && ch <= '9') || ch == '.') {
                str += ch;
            }
        }
        tradeVoList.add(new TradeVo(carbonMarketVo.getInfoList().get(0), str, "全国市场"));

        result = queryMarketInfo(1);
        list = (List) result.getData();
        EuropeCarbonMarketVo vo = (EuropeCarbonMarketVo) list.get(0);
        tradeVoList.add(new TradeVo(vo.getYear(), vo.getPrice(), "欧洲市场"));

        result = queryMarketInfo(2);
        list = (List) result.getData();
        vo = (EuropeCarbonMarketVo) list.get(0);
        tradeVoList.add(new TradeVo(vo.getYear(), vo.getPrice(), "美国市场"));

        result = queryMarketInfo(3);
        list = (List) result.getData();
        vo = (EuropeCarbonMarketVo) list.get(0);
        tradeVoList.add(new TradeVo(vo.getYear(), vo.getPrice(), "韩国市场"));

        result = queryMarketInfo(4);
        list = (List) result.getData();
        vo = (EuropeCarbonMarketVo) list.get(0);
        tradeVoList.add(new TradeVo(vo.getYear(), vo.getPrice(), "北京市场"));

        result = queryMarketInfo(5);
        list = (List) result.getData();
        vo = (EuropeCarbonMarketVo) list.get(0);
        tradeVoList.add(new TradeVo(vo.getYear(), vo.getPrice(), "上海市场"));

        result = queryMarketInfo(6);
        list = (List) result.getData();
        vo = (EuropeCarbonMarketVo) list.get(0);
        tradeVoList.add(new TradeVo(vo.getYear(), vo.getPrice(), "深圳市场"));

        result = queryMarketInfo(7);
        list = (List) result.getData();
        vo = (EuropeCarbonMarketVo) list.get(0);
        tradeVoList.add(new TradeVo(vo.getYear(), vo.getPrice(), "广东市场"));

        return ResponseResult.okResult(tradeVoList);
    }

    @Override
    public ResponseResult buyCarbon(CarbonTradeDto dto) {
        String type = dto.getType();
        Double num = dto.getNum();
        Double price = dto.getPrice();
        Double totalPrice = dto.getTotalPrice();
        CarbonTrading carbonTrading = new CarbonTrading();
        carbonTrading.setCreateTime(new Date());
        carbonTrading.setTradeType(1);
        carbonTrading.setTradeQuantity(num);
        carbonTrading.setTradePrice(price);
        carbonTrading.setDelFlag(0);
        carbonTrading.setArea(dto.getArea());
        carbonTrading.setQuotaType("ccer".equals(type) ? 1 : 0);
        this.save(carbonTrading);
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult sellCarbon(CarbonTradeDto dto) {
        String type = dto.getType();
        Double num = Math.abs(dto.getNum()) * -1;
        Double price = dto.getPrice();
        Double totalPrice = dto.getTotalPrice();
        CarbonTrading carbonTrading = new CarbonTrading();
        carbonTrading.setCreateTime(new Date());
        carbonTrading.setTradeType(0);
        carbonTrading.setTradeQuantity(num);
        carbonTrading.setTradePrice(price);
        carbonTrading.setDelFlag(0);
        carbonTrading.setArea(dto.getArea());
        carbonTrading.setQuotaType("ccer".equals(type) ? 1 : 0);
        this.save(carbonTrading);
        return ResponseResult.okResult();
    }

}